package org.zoomdev.zoom.dao.structs.impl;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.zoomdev.zoom.common.utils.Classes;
import org.zoomdev.zoom.dao.Dao;
import org.zoomdev.zoom.dao.DatabaseStruct;
import org.zoomdev.zoom.dao.Sql;
import org.zoomdev.zoom.dao.SqlDriver;
import org.zoomdev.zoom.dao.impl.SimpleSelect;
import org.zoomdev.zoom.dao.structs.ColumnMeta;
import org.zoomdev.zoom.dao.structs.TableMeta;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public abstract class BaseDatabaseStruct implements DatabaseStruct {

    protected final static Log log = LogFactory.getLog(Dao.class);

    protected final String name;
    private final Dao dao;
    private final SqlDriver driver;
    private final Map<String, TableMeta> cache = new ConcurrentHashMap<>();

    public BaseDatabaseStruct(Dao dao, String name) {
        this.dao = dao;
        this.driver = dao.sqlDriver();
        this.name = name;
    }


    public TableMeta getTableMeta(String table) {
        assert (table != null);
        return cache.computeIfAbsent(table.toLowerCase(), k -> {
            SimpleSelect select = new SimpleSelect();
            select.from(table);
            select.where("1", Sql.PlaceHolder.of("2"));
            return dao.execute(connection -> {
                try (PreparedStatement ps = connection.prepareStatement(select.buildSelect())) {
                    try (ResultSet rs = ps.executeQuery()) {
                        ResultSetMetaData data = rs.getMetaData();
                        List<ColumnMeta> columnMetas = new ArrayList<>(data.getColumnCount());
                        TableMeta tableMeta = new TableMeta();
                        tableMeta.setName(table);
                        tableMeta.setColumns(columnMetas);
                        for (int i = 1, c = data.getColumnCount(); i <= c; ++i) {
                            ColumnMeta column = new ColumnMeta();
                            column.setTableMeta(tableMeta);
                            column.setColumnType(Classes.forName(data.getColumnClassName(i)));
                            column.setType(data.getColumnType(i));
                            column.setName(data.getColumnName(i));
                            columnMetas.add(column);
                        }
                        try {
                            select.clear();
                            fill(tableMeta, connection, select);
                        } catch (SQLException ex) {
                            log.warn("无法从数据库源获取表结构:[" + tableMeta.getName() + "]");
                        }
                        return tableMeta;
                    }
                }
            });

        });
    }

    protected abstract TableMeta fill(TableMeta meta, Connection dao, SimpleSelect select) throws SQLException;

}
